// iclwrap.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

static void print_usage()
{
	_putts(_T("Usage: iclwrap [executable] [arguments...]"));
}

static bool ContainsAtLeastNTimesThisCharacter(LPCTSTR str,_TCHAR c,int count)
{
	LPCTSTR sz = str;
	for (int i=0;i<count;++i)
	{
		sz = _tcschr(sz,c);
		if (sz==NULL)
		{
			return false;
		}

		sz++;
	}

	return true;
}

static bool ContainsSpaces(LPCTSTR str)
{
	if (_tcschr(str,_T(' ')))
	{
		return true;
	}

	return false;
}

static bool IsUnixFileName(LPCTSTR str)
{
	if (*str==_T('-'))
	{
		return false;
	}

	// see if we have at least one slash and a dot
	if ((ContainsAtLeastNTimesThisCharacter(str,_T('/'),1)|| ContainsAtLeastNTimesThisCharacter(str,_T('\\'),1)) &&
		ContainsAtLeastNTimesThisCharacter(str,_T('.'),1))
	{
		return true;
	}

	return false;
}

static bool StartsWithFollowedByUnixFileName(LPCTSTR startsWith,LPCTSTR str)
{
	size_t len = _tcslen(startsWith);
	if (_tcsncmp(str,startsWith,len)!=0)
	{
		return false;
	}

	return IsUnixFileName(str + len);
}

static tstring ConvertFileName(LPCTSTR fileName)
{
	tstring fileNameConv(fileName);
	std::replace( fileNameConv.begin(), fileNameConv.end(), _T('\\'), _T('/'));
	tstring cmdLine(_T("cygpath.exe -w \""));
	////tstring cmdLine(_T("\"C:\\Program Files (x86)\\cygwin\\bin\\cygpath.exe\" -w \""));
	cmdLine += fileNameConv;
	cmdLine += _T('"');
	FILE* fp = _wpopen(cmdLine.c_str(),L"rt");
	if (fp==NULL)
	{
		return tstring(_T("INVALID"));
	}

	TCHAR buffer[MAX_PATH * 2];
	buffer[0] = 0;
	// read until end-of-stream or an error occurs
	_fgetts(buffer,ARRAYSIZE(buffer),fp);
	tstring retVal;
	size_t len = _tcslen(buffer);
	if (len>0)
	{
		// remove trailing linefeed/carriage return
		for (size_t i = len-1;i>=0&&(buffer[i]==_T('\r')||buffer[i]==_T('\n'));--i)
		{
			buffer[i]=_T('\0');
		}

		retVal = buffer;
	}
	else
	{
		retVal = _T("INVALID");
	}

	fclose(fp);
	return retVal;
}

static vector<tstring> TweakArguments(int argCount,const _TCHAR* const* args)
{
	vector<tstring> tweakedArgs;
	tweakedArgs.reserve(argCount);

	for (int i=0;i<argCount;++i)
	{
		if (IsUnixFileName(args[i]))
		{
			tweakedArgs.push_back(ConvertFileName(args[i]));
		}
		else if (StartsWithFollowedByUnixFileName(_T("-Fo:"),args[i]))
		{
			tweakedArgs.push_back(tstring(_T("-Fo:"))+ConvertFileName(4+args[i]));
		}
		else if (StartsWithFollowedByUnixFileName(_T("-out:"),args[i]))
		{
			tweakedArgs.push_back(tstring(_T("-out:"))+ConvertFileName(5+args[i]));
		}
		else
		{
			tweakedArgs.push_back(tstring(args[i]));
		}
	}

	return tweakedArgs;
}

static int ExecCommand(LPCTSTR cmdLine)
{
	size_t len = _tcslen(cmdLine);
	TCHAR* cmdlineCopy = (TCHAR*)_malloca((len+1)*sizeof(TCHAR));
	_tcsncpy_s(cmdlineCopy,len+1,cmdLine,len);
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	DWORD exit_code;

	BOOL B = CreateProcess(NULL, cmdlineCopy, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
	_freea(cmdlineCopy);
	if (B) 
	{
		WaitForSingleObject(pi.hProcess, INFINITE);


		if (!GetExitCodeProcess(pi.hProcess, &exit_code))
			exit_code = -1;


		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);


		return exit_code;
	} else {
		return -1;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// the first argument is the executable to wrap - either icl or xilink
	if (argc < 2)
	{
		print_usage();
		return EXIT_FAILURE;
	}

	auto tweakedArgs = TweakArguments(argc-2,&argv[2]);

	tstring cmdLine(argv[1]);
	for (auto it = tweakedArgs.begin();it!=tweakedArgs.end();++it)
	{
		cmdLine += _T(' ');
		if (ContainsSpaces(it->c_str()))
		{
			cmdLine += _T('"');
			cmdLine += *it;
			cmdLine += _T('"');
		}
		else
		{
			cmdLine += *it;
		}
	}

	//_putts(cmdLine.c_str());

	int r = ExecCommand(cmdLine.c_str());

	return r;
}

